//
//  HACRouterMacro.h
//  HACRouter
//
//  Created by Chengjie on 2019/5/1.
//

#ifndef HACRouterMacro_h
#define HACRouterMacro_h
#import "metamacros.h"
#import <objc/runtime.h>

#define metamacro_concat_all(...)                       \
        metamacro_concat(metamacro_concat_all,metamacro_argcount(__VA_ARGS__))(__VA_ARGS__)

#define metamacro_concat_all1(...) __VA_ARGS__
#define metamacro_concat_all2(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all1(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all3(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all2(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all4(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all3(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all5(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all4(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all6(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all5(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all7(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all6(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all8(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all7(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all9(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all8(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all10(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all9(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all11(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all10(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all12(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all11(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all13(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all12(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all14(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all13(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all15(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all14(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all16(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all15(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all17(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all16(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all18(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all17(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all19(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all18(metamacro_tail(__VA_ARGS__)))
#define metamacro_concat_all20(...) metamacro_concat(metamacro_head(__VA_ARGS__),metamacro_concat_all19(metamacro_tail(__VA_ARGS__)))


#define metamacro_delete_last(...) metamacro_take(metamacro_dec( metamacro_argcount(__VA_ARGS__)) , __VA_ARGS__)

// 遍历
#define HAC_ROUTER_FOREACH_ARGS(MACRO, ...)                                                         \
        metamacro_if_eq(1,metamacro_argcount(__VA_ARGS__))                                          \
        ()                                                                                          \
        (metamacro_foreach(MACRO,, metamacro_tail(__VA_ARGS__)))                                    \

// 取得nullable
#define HAC_ROUTER_IS_NULLABLE_CHECK__nullable ,
#define HAC_ROUTER_IS_NULLABLE_CHECK_Nullable ,
#define HAC_ROUTER_IS_NULLABLE_(...)                                                                \
        metamacro_if_eq(metamacro_argcount( HAC_ROUTER_IS_NULLABLE_CHECK ## __VA_ARGS__),           \
        metamacro_inc(metamacro_argcount(__VA_ARGS__)))

#define HAC_ROUTER_IS_NULLABLE_1_(...) HAC_ROUTER_IS_NULLABLE_CHECK ## __VA_ARGS__ ,
#define HAC_ROUTER_IS_NULLABLE_2_(...) __VA_ARGS__ ,
#define HAC_ROUTER_GET_IS_NULLABLE(...)                                                             \
        metamacro_if_eq(                                                                            \
        metamacro_argcount(HAC_ROUTER_IS_NULLABLE_1_ __VA_ARGS__),                                  \
        metamacro_inc(metamacro_argcount(HAC_ROUTER_IS_NULLABLE_2_ __VA_ARGS__))                    \
        )

// 取得类型 删掉nullable
#define HAC_ROUTER_GET_TYPE_SET__nullable
#define HAC_ROUTER_GET_TYPE_SET_Nullable
#define HAC_ROUTER_GET_TYPE_(...)                                                                   \
        HAC_ROUTER_IS_NULLABLE_(__VA_ARGS__)                                                        \
        (HAC_ROUTER_GET_TYPE_SET ## __VA_ARGS__,)                                                   \
        (__VA_ARGS__,)

#define HAC_ROUTER_GET_TYPE(...)                                                                    \
        metamacro_delete_last( HAC_ROUTER_GET_TYPE_ __VA_ARGS__ )

// 取得变量
#define HAC_ROUTER_GET_VAR_(...)
#define HAC_ROUTER_GET_VAR(...) HAC_ROUTER_GET_VAR_ __VA_ARGS__

// 实际使用
#define HAC_ROUTER_PARAMS_LINE_VALUE(INDEX,VALUE)                                                   \
        ,metamacro_concat(_,HAC_ROUTER_GET_VAR(VALUE))

#define HAC_ROUTER_PARAMS_VALUE_SEL_VALUE(INDEX,VALUE)                                              \
        HAC_ROUTER_GET_VAR(VALUE) : HAC_ROUTER_GET_VAR(VALUE)

#define HAC_ROUTER_PARAMS_VAR_SEL_TYPE_VAR(INDEX,VALUE)                                             \
        HAC_ROUTER_GET_VAR(VALUE) : (HAC_ROUTER_GET_TYPE(VALUE)) HAC_ROUTER_GET_VAR(VALUE)


#define HAC_ROUTER_FUNCTION_PARAM_DEFINE(PREFIX,PREFIX2,MACRO, ...)                                 \
        metamacro_concat_all(PREFIX ,                                                               \
        metamacro_if_eq(1,metamacro_argcount(1,##__VA_ARGS__))()(PREFIX2),                          \
        HAC_ROUTER_FOREACH_ARGS(MACRO,1,##__VA_ARGS__))                                             \

#define HAC_ROUTER_PARAMS_DOT_TYPEOF_TYPE_VALUE_FIRST_NO_DOT(INDEX,VALUE)                           \
        metamacro_if_eq(0,INDEX)()(,)                                                               \
        typeof( HAC_ROUTER_GET_TYPE(VALUE))  HAC_ROUTER_GET_VAR(VALUE)

#define HAC_ROUTER_CREATE_SEL_STR(INDEX,VALUE)                                                      \
        metamacro_stringify(HAC_ROUTER_GET_VAR(VALUE)) ":"

#define HAC_ROUTER_PARAMS_DOT_TYPEOF_VALUE(INDEX,VALUE)                                             \
        ,typeof(HAC_ROUTER_GET_VAR(VALUE))

#define HAC_ROUTER_PARAMS_DOT_AND_VALUE(INDEX,VALUE)                                                \
        ,HAC_ROUTER_GET_VAR(VALUE)



// 用来提取注册信息
#define HAC_FUN_ARG_STR(...)                                                                        \
        metamacro_if_eq(1,metamacro_argcount(1,##__VA_ARGS__))                                      \
                                                        (void)                                      \
        (                                                                                           \
            HAC_ROUTER_FOREACH_ARGS(HAC_ROUTER_PARAMS_DOT_TYPEOF_TYPE_VALUE_FIRST_NO_DOT,           \
                                                                        1,##__VA_ARGS__ )           \
        )                                                                                           \

#define HAC_NS_STR(MACRO_STR)  @# MACRO_STR

#define HAC_ROUTER_FUNCTION_PARAM_SELNAME(PREFIX,PREFIX2,MACRO, ...)                                \
        @metamacro_stringify(PREFIX)                                                                \
        metamacro_stringify(                                                                        \
            metamacro_if_eq(1,metamacro_argcount(1,##__VA_ARGS__))()(PREFIX2)                       \
        )                                                                                           \
        HAC_ROUTER_FOREACH_ARGS(MACRO,1,##__VA_ARGS__)                                              \

/**
 DEBUG模式下输出所有注册的路由路径LOG文本，方便业务方调用

 @param TIP_MAC_STR 提示这个路由路径是干什么用的：比如详情页、首页、我的等等
 @param PATH 控制器对应的标识，和URL相对路径相似,但是以“_”下划线作为连接符，如goods_detail
 @param CONTROLLER 当前类
 @param ... 在调试阶段输出log日志的宏
 @return void
 */
#define HAC_COLLECT_ROUTER_PATH_IMP(TIP_MAC_STR, PATH, CONTROLLER, ...)                                                                         \
        extern void regest_router_key_value(NSString *router_key, NSString *controller_name, NSString *router_imp, NSString *sel_name);                             \
        __attribute__((constructor)) static void                                                                                                \
        HAC_ROUTER_FUNCTION_PARAM_DEFINE(hac_regist_router_##PATH##_controller,                                                                 \
                                                                         _with,                                                                 \
                                                  HAC_ROUTER_PARAMS_LINE_VALUE,                                                                 \
                                                                 ##__VA_ARGS__)                                                                 \
        (void)                                                                                                                                  \
        {                                                                                                                                       \
            regest_router_key_value(HAC_NS_STR(PATH), HAC_NS_STR(CONTROLLER), HAC_NS_STR(HAC_USE_ROUTER(TIP_MAC_STR, PATH, ##__VA_ARGS__)),     \
                                    HAC_ROUTER_FUNCTION_PARAM_SELNAME(init_with_##PATH,                                                         \
                                                                                    _,                                                          \
                                                            HAC_ROUTER_CREATE_SEL_STR,                                                          \
                                                                       ##__VA_ARGS__)                                                           \
                                    );                                                                                                          \
        }                                                                                                                                       \


/**
 初始化注册路由:使用示范
 
 @implementation ViewController
 
 - (void)viewDidLoad {
    [super viewDidLoad];
 
 }
 
 ....
 
 HAC_INIT_ROUTER(详情页-姓名-年龄, goods_detail, ViewController, (NSString *)name, (NSInteger)age) {
    self = [super init];
    if (self) {
 
    }
    return self;
 }
 
 HAC_INIT_ROUTER(详情页, goods_detail, ViewController) {
    self = [super init];
    if (self) {
 
    }
    return self;
 }
 
 HAC_INIT_ROUTER(详情页-回调, goods_detail, ViewController, (void(^)(NSString *name, NSInteger age))complete) {
    self = [super init];
    if (self) {
        self.complete = complete;
    }
    return self;
 }

 - (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    if (self.complete) {
        self.complete(@"jack", 16);
    }
 }
 
 .....
 
 @end
 
 @param TIP_MAC_STR 提示这个路由路径是干什么用的：比如详情页、首页、我的等等
 @param PATH 控制器对应的标识，和URL相对路径相似,但是以“_”下划线作为连接符，如goods_detail
 @param CONTROLLER 当前类
 @param ... 可变参数列表- (type)name, (type1)name1, (type2)name2 ,...
 @return 返回当前类的对象
 */

#if DEBUG_ROUTER

#define HAC_INIT_ROUTER(TIP_MAC_STR, PATH, CONTROLLER, ...)                                             \
        HAC_COLLECT_ROUTER_PATH_IMP(TIP_MAC_STR, PATH, CONTROLLER, ##__VA_ARGS__)                       \
        + (instancetype)HAC_ROUTER_FUNCTION_PARAM_DEFINE(hac_create_##PATH##_controller,                \
                                                                                _with_,                 \
                                                    HAC_ROUTER_PARAMS_VAR_SEL_TYPE_VAR,                 \
                                                                         ##__VA_ARGS__)                 \
        {                                                                                               \
            return [[self alloc] HAC_ROUTER_FUNCTION_PARAM_DEFINE(init_with_##PATH,                     \
                                                                                 _,                     \
                                                 HAC_ROUTER_PARAMS_VALUE_SEL_VALUE,                     \
                                                                     ##__VA_ARGS__)];                   \
        }                                                                                               \
        - (instancetype)HAC_ROUTER_FUNCTION_PARAM_DEFINE(init_with_##PATH,                              \
                                                                        _,                              \
                                       HAC_ROUTER_PARAMS_VAR_SEL_TYPE_VAR,                              \
                                                            ##__VA_ARGS__)                              \

#else

#define HAC_INIT_ROUTER(TIP_MAC_STR, PATH, CONTROLLER, ...)                                             \
        HAC_COLLECT_ROUTER_PATH_IMP(TIP_MAC_STR, PATH, CONTROLLER, ##__VA_ARGS__)                       \
        id HAC_ROUTER_FUNCTION_PARAM_DEFINE(hac_use_path_##PATH##_controller,                           \
                                                                         _with,                         \
                                                  HAC_ROUTER_PARAMS_LINE_VALUE,                         \
                                                                 ##__VA_ARGS__)                         \
                (                                                                                       \
                    metamacro_if_eq(1,metamacro_argcount(1,##__VA_ARGS__))(void)                        \
                    (                                                                                   \
                        HAC_ROUTER_FOREACH_ARGS(HAC_ROUTER_PARAMS_DOT_TYPEOF_TYPE_VALUE_FIRST_NO_DOT,   \
                                                                                    1,##__VA_ARGS__ )   \
                    )                                                                                   \
                )                                                                                       \
        {                                                                                               \
            return [CONTROLLER HAC_ROUTER_FUNCTION_PARAM_DEFINE(hac_create_##PATH##_controller,         \
                                                                                        _with_,         \
                                                             HAC_ROUTER_PARAMS_VALUE_SEL_VALUE,         \
                                                                                 ##__VA_ARGS__)];       \
        }                                                                                               \
        + (instancetype)HAC_ROUTER_FUNCTION_PARAM_DEFINE(hac_create_##PATH##_controller,                \
                                                                                 _with_,                \
                                                     HAC_ROUTER_PARAMS_VAR_SEL_TYPE_VAR,                \
                                                                         ##__VA_ARGS__)                 \
        {                                                                                               \
            return [[self alloc] HAC_ROUTER_FUNCTION_PARAM_DEFINE(init_with_##PATH,                     \
                                                                                 _,                     \
                                                 HAC_ROUTER_PARAMS_VALUE_SEL_VALUE,                     \
                                                                     ##__VA_ARGS__)];                   \
        }                                                                                               \
        - (instancetype)HAC_ROUTER_FUNCTION_PARAM_DEFINE(init_with_##PATH,                              \
                                                                        _,                              \
                                       HAC_ROUTER_PARAMS_VAR_SEL_TYPE_VAR,                              \
                                                            ##__VA_ARGS__)                              \

#endif

/**
 使用已注册的路由:使用示范
 
 @implementation XXX
 
 ...
 
 HAC_USE_ROUTER(详情页-姓名-年龄, goods_detail, (NSString *)name, (NSInteger)age)
 - (void)jumpToGoodsDetail {
    ViewController *vc = hac_use_path_goods_detail_controller_with_name_age(@"jack", 16);
    [self.navigationController pushViewController:vc animated:YES];
 }

 ...
 
 @end
 
 @param TIP_MAC_STR 提示这个路由路径是干什么用的：比如详情页、首页、我的等等
 @param PATH 控制器对应的标识，和URL相对路径相似,但是以“_”下划线作为连接符，如goods_detail
 @param ... 可变参数列表- (type)name, (type1)name1, (type2)name2 ,...
 @return 返回PATH映射的类的对象
 */

#if DEBUG_ROUTER

#define HAC_USE_ROUTER(TIP_MAC_STR, PATH, ...)\
        static id HAC_ROUTER_FUNCTION_PARAM_DEFINE(hac_use_path_##PATH##_controller,                    \
                                                                              _with,                    \
                                                       HAC_ROUTER_PARAMS_LINE_VALUE,                    \
                                                                      ##__VA_ARGS__)                    \
                  (                                                                                     \
                    metamacro_if_eq(1,metamacro_argcount(1,##__VA_ARGS__))(void)                        \
                    (                                                                                   \
                        HAC_ROUTER_FOREACH_ARGS(HAC_ROUTER_PARAMS_DOT_TYPEOF_TYPE_VALUE_FIRST_NO_DOT,   \
                                                                                    1,##__VA_ARGS__ )   \
                    )                                                                                   \
                  )                                                                                     \
                {                                                                                       \
                    Class theClass = [HACRouter getClassForPath:HAC_NS_STR(PATH)];                      \
                    NSString *selName = HAC_ROUTER_FUNCTION_PARAM_SELNAME(                              \
                                                      hac_create_##PATH##_controller,                   \
                                                                              _with_,                   \
                                                           HAC_ROUTER_CREATE_SEL_STR,                   \
                                                                        ##__VA_ARGS__);                 \
                    SEL theSel = NSSelectorFromString(selName);                                         \
                    id(*imp)(id,SEL                                                                     \
                    HAC_ROUTER_FOREACH_ARGS(HAC_ROUTER_PARAMS_DOT_TYPEOF_VALUE,1,##__VA_ARGS__  )) =    \
                    (void*)class_getMethodImplementation(object_getClass(theClass), theSel);            \
                    return imp(theClass, theSel                                                         \
                           HAC_ROUTER_FOREACH_ARGS(HAC_ROUTER_PARAMS_DOT_AND_VALUE,1,##__VA_ARGS__));   \
                }                                                                                       \


#else

#define HAC_USE_ROUTER(TIP_MAC_STR, PATH, ...)                                                          \
        extern id HAC_ROUTER_FUNCTION_PARAM_DEFINE(hac_use_path_##PATH##_controller,                    \
                                                                                _with,                  \
                                                         HAC_ROUTER_PARAMS_LINE_VALUE,                  \
                                                                        ##__VA_ARGS__)                  \
                  (                                                                                     \
                    metamacro_if_eq(1,metamacro_argcount(1,##__VA_ARGS__))(void)                        \
                    (                                                                                   \
                        HAC_ROUTER_FOREACH_ARGS(HAC_ROUTER_PARAMS_DOT_TYPEOF_TYPE_VALUE_FIRST_NO_DOT,   \
                                                                                    1,##__VA_ARGS__ )   \
                    )                                                                                   \
                  );                                                                                    \

#endif

#endif /* HACRouterMacro_h */
